package com.hiray.calendar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by hiray on 2018/2/26.
 *
 * @author hiray
 */


public class CalendarMonthView extends View {
    private static final String TAG = "CalendarMonthView";
    private Paint lastMonthPainter;
    private Paint thisMonthPainter;
    private Paint nextMonthPainter;
    private Paint gridPainter;
    private Paint lunarHolidayPainter;
    private int rowSize;
    private int columnSize;
    //year and month of this page
    private int mYear = 1900;
    private int mMonth = 0;
    private boolean mShowGrid;
    private int mGridWidth;
    private int mGridColor;
    private boolean mShowHoliday;
    private boolean mShowLunar;
    private int mHolidayLunarTextSize;
    private int mHolidayLunarTextColor;
    private GestureDetector mGestureDetector;
    private int[][] dates = new int[6][7];
    private OnDateClickListener mOnDateClickListener;
    private int mRows;

    public interface OnDateClickListener {
        void onDateClick(int year, int month, int date);
    }

    public void setOnDateClickListener(OnDateClickListener onDateClickListener) {
        this.mOnDateClickListener = onDateClickListener;
    }

    public CalendarMonthView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CalendarMonthView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typeArr = context.obtainStyledAttributes(attrs, R.styleable.CalendarMonthView);
        mShowGrid = typeArr.getBoolean(R.styleable.CalendarMonthView_show_grid, false);
        mGridWidth = typeArr.getDimensionPixelSize(R.styleable.CalendarMonthView_grid_width, 2);
        mGridColor = typeArr.getColor(R.styleable.CalendarMonthView_grid_color, Color.parseColor("#CCCCCC"));
        mShowHoliday = typeArr.getBoolean(R.styleable.CalendarMonthView_show_holiday, false);
        mShowLunar = typeArr.getBoolean(R.styleable.CalendarMonthView_show_lunar, false);
        mHolidayLunarTextColor = typeArr.getColor(R.styleable.CalendarMonthView_lunar_holiday_textColor, Color.parseColor("#cccccc"));
        mHolidayLunarTextSize = typeArr.getDimensionPixelSize(R.styleable.CalendarMonthView_lunar_holiday_textSize, 21);
        typeArr.recycle();
        initPainter();
        initGestureDetector();
    }

    private void initGestureDetector() {
        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                processClick(e);
                return true;
            }
        });
    }

    private void processClick(MotionEvent e) {
        int x = (int) e.getX(), y = (int) e.getY();
        int column = x / columnSize, row = y / rowSize;
        //计算出点击的year,month，day
        //计算落在那个区域里面
        int nowYear, nowMonth, nowDate;
        int weekDay = CalendarUtil.firstDayOfWeek(mYear, mMonth);
        int lastYear = mYear, lastMonth = mMonth, nextYear, nextMonth, thisMonthEndRow, thisMonthEndColumn;
        if (mMonth == 11) {
            lastYear = mYear - 1;
            lastMonth = 11;
            nextMonth = 0;
            nextYear = mYear + 1;
        } else {
            lastMonth = mMonth - 1;
            nextMonth = mMonth + 1;
            nextYear = mYear;
        }

        int daysOfMonth = CalendarUtil.daysOfMonth(mYear, mMonth);
        thisMonthEndRow = (daysOfMonth - (7 - weekDay + 1)) / 7 + 1;
        thisMonthEndColumn = (daysOfMonth - weekDay + 1) % 7 - 1;
        nowDate = dates[row][column];
        if (row == 0 && column <= weekDay - 2) {
            nowYear = lastYear;
            nowMonth = lastMonth;
        } else if (row < thisMonthEndRow || (row == thisMonthEndRow && column <= thisMonthEndColumn)) {
            nowYear = mYear;
            nowMonth = mMonth;
        } else {
            nowYear = nextYear;
            nowMonth = nextMonth;
        }
        if (mOnDateClickListener != null)
            mOnDateClickListener.onDateClick(nowYear, nowMonth, nowDate);

    }

    public void set(int year, int month) {
        this.mYear = year;
        this.mMonth = month;
        requestLayout();
        invalidate();
    }

    private void initPainter() {
        lastMonthPainter = new Paint(Paint.ANTI_ALIAS_FLAG);
        lastMonthPainter.setStyle(Paint.Style.FILL_AND_STROKE);
        lastMonthPainter.setColor(Color.GRAY);
        lastMonthPainter.setTextSize(38);
        thisMonthPainter = new Paint(lastMonthPainter);
        thisMonthPainter.setColor(Color.BLACK);
        nextMonthPainter = new Paint(lastMonthPainter);
        nextMonthPainter.setColor(Color.RED);
        gridPainter = new Paint(Paint.ANTI_ALIAS_FLAG);
        gridPainter.setStrokeWidth(mGridWidth);
        gridPainter.setStyle(Paint.Style.STROKE);
        gridPainter.setColor(mGridColor);
        lunarHolidayPainter = new Paint(Paint.ANTI_ALIAS_FLAG);
        lunarHolidayPainter.setTextSize(mHolidayLunarTextSize);
        lunarHolidayPainter.setColor(mHolidayLunarTextColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int defaultWidth = MeasureSpec.getSize(widthMeasureSpec);
        int defaultHeight = MeasureSpec.getSize(heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST) {
            defaultWidth = getResources().getDisplayMetrics().densityDpi * 200;
        }
        if (heightMode == MeasureSpec.AT_MOST) {
            defaultHeight = getResources().getDisplayMetrics().densityDpi * 200;
        }
        setMeasuredDimension(defaultWidth, defaultHeight);
        mRows = CalendarUtil.rowsOfMonth(mYear, mMonth);
        rowSize = defaultHeight / mRows;
        columnSize = defaultWidth / 7;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        if (mShowGrid)
            drawGrid(canvas);

        int year = mYear;
        int month = mMonth;
        int weekDay = CalendarUtil.firstDayOfWeek(year, month);

        int lastMonth, lastYear;
        if (month == 0) {
            lastYear = year - 1;
            lastMonth = 11;
        } else {
            lastYear = year;
            lastMonth = month - 1;
        }
        drawLastMonth(canvas, lastYear, lastMonth, weekDay - 1);
        int[] rc = drawThisMonth(canvas, year, month, weekDay - 1);
        drawNextMonth(canvas, rc[0], rc[1]);
    }

    private void drawGrid(Canvas canvas) {
        float startX = 0, startY, endX = getMeasuredWidth(), endY;
        for (int i = 0; i < mRows + 1; i++) {
            if (i == 0)
                startY = endY = gridPainter.getStrokeWidth() / 2;
            else if (i == mRows)
                startY = endY = getMeasuredHeight() - gridPainter.getStrokeWidth() / 2;
            else startY = endY = rowSize * i;
            canvas.drawLine(startX, startY, endX, endY, gridPainter);
        }

        startY = 0;
        endY = getMeasuredHeight();
        for (int i = 0; i < 8; i++) {
            if (i == 0)
                startX = endX = gridPainter.getStrokeWidth() / 2;
            else if (i == 7)
                startX = endX = getMeasuredWidth() - gridPainter.getStrokeWidth() / 2;
            else
                startX = endX = columnSize * i;

            canvas.drawLine(startX, startY, endX, endY, gridPainter);
        }
    }

    private void drawNextMonth(Canvas canvas, int row, int column) {
        float startX, baseline, textLen;
        Paint.FontMetrics fm = nextMonthPainter.getFontMetrics();
        baseline = (fm.bottom - fm.top) / 2 - fm.bottom + rowSize / 2 + row * rowSize;
        int date = 1, r = row;
        while (true) {
            if (column == 7) {
                if (r >= mRows - 1)
                    break;
                r++;
                column = 0;
                baseline += rowSize;
            }
            String text = String.valueOf(date);
            textLen = nextMonthPainter.measureText(text);
            startX = column * columnSize + (columnSize - textLen) / 2;
            canvas.drawText(text, startX, baseline, nextMonthPainter);
            dates[row][column] = date;
            column++;
            date++;
        }
    }

    private int[] drawThisMonth(Canvas canvas, int year, int month, int i) {
        int[] r = new int[2];
        int line = i, row = 0, column = i;
        float startX, baseline, textLen;
        int days = CalendarUtil.daysOfMonth(year, month);

        Paint.FontMetrics fm = thisMonthPainter.getFontMetrics();
        baseline = (fm.bottom - fm.top) / 2 - fm.bottom + rowSize / 2;
        for (int j = 1; j <= days; j++) {
            //change color
            dates[row][column] = j;
            String text = String.valueOf(j);
            textLen = thisMonthPainter.measureText(text);
            startX = column * columnSize + (columnSize - textLen) / 2;
            if (CalendarUtil.isToday(mYear, mMonth, j))
                drawWithColor(canvas, text, startX, baseline, thisMonthPainter, Color.MAGENTA);
            else canvas.drawText(text, startX, baseline, thisMonthPainter);
            line++;
            column++;
            if (line % 7 == 0) {
                row++;
                column = 0;
                baseline += rowSize;
            }
        }
        r[0] = row;
        r[1] = column;
        return r;
    }

    private void drawWithColor(Canvas canvas, String text, float startX, float baseline, Paint paint, int color) {
        int c = paint.getColor();
        paint.setColor(color);
        canvas.drawText(text, startX, baseline, paint);
        paint.setColor(c);
    }

    /**
     * @param canvas the canvas on which we draw date
     * @param year   year
     * @param month  month
     * @param number how many days we can draw for last month
     */
    private void drawLastMonth(Canvas canvas, int year, int month, int number) {
        int startDate = CalendarUtil.daysOfMonth(year, month) - number + 1;
        float startX, baseline, textLen;
        Paint.FontMetrics fm = lastMonthPainter.getFontMetrics();
        baseline = (fm.bottom - fm.top) / 2 - fm.bottom + rowSize / 2;

        for (int i = 0; i < number; i++) {
            dates[0][i] = startDate;
            String text = String.valueOf(startDate++);
            textLen = lastMonthPainter.measureText(text);
            startX = i * columnSize + (columnSize - textLen) / 2;
            canvas.drawText(text, startX, baseline, lastMonthPainter);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        return mGestureDetector.onTouchEvent(event);
    }
}
